// Find all of the prime numbers between 2 and N
//

#include <iostream>
#include <sstream>
#include <format>
#include <cmath>
#include <vector>
#include <thread>

#include <Windows.h>

bool IsPrime(unsigned int n)
{
	// for (unsigned int i = 2; i <= n / 2; ++i)
	for (unsigned int i = 2; i <= std::sqrtf(n * 1.0f); ++i)
	{
		if (n % i == 0)
			return false;
	}

	return true;
}

void findPrime(unsigned int from, unsigned int to, std::vector<unsigned int>& result)
{
	// output all of the prime numbers between from and to
	for (unsigned int i = from; i < to; ++i)
	{
		if (IsPrime(i)) {
			result.push_back(i);
		}
	}
}

int main()
{
	// output all of the prime numbers between 2 and 500k(500,000)
	std::vector<unsigned int> v1;
	// findPrime(2, 500000, v1);
	std::thread task1 = std::thread(findPrime, 2, 500000, std::ref(v1));
	// SetThreadAffinityMask(task1.native_handle(), 0x01);

	// output all of the prime numbers between 500k(500,000) and 1M(1,000,000)
	std::vector<unsigned int> v2;
	// findPrime(500000, 1000000, v2);
	std::thread task2 = std::thread(findPrime, 500001, 1000000, std::ref(v2));
	// SetThreadAffinityMask(task2.native_handle(), 0x02);

	// wait for the threads to finish
	task1.join();
	task2.join();

	// Disable Parallel Loading
	// HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<image.exe>\MaxLoaderThreads DWORD 1
	// SetThreadAffinityMask

	// output
	std::stringstream ss;

	for (int i = 0; i < v1.size(); i++) {
		ss << v1[i] << " ";
		if(i % 10 == 0)
			ss << std::endl;
	}

	for (int i = 0; i < v2.size(); i++) {
		ss << v2[i] << " ";
		if (i % 10 == 0)
			ss << std::endl;
	}

	ss << std::endl;
	ss << "total: " << v1.size() + v2.size()
		<< " = " << v1.size() << " + " << v2.size() << std::endl;

	// to screen
	std::cout << ss.str() << std::endl;
	return 0;
}